vlwkaos' digital garden

GraphQL - Query and Mutation

Fields

GraphQL은 객체의 특정 필드 값을 받아오기 위해 사용할 수 있다. 쿼리와 결과는 같은 구조를 띈다.

예를 들어, 아래의 쿼리는

{
  hero {
    name
    # 주석은 이런식으로 달 수 있다
    # 아래처럼 오브젝트에 대한 쿼리를 날릴 수도 있다.
    friends {
      name
    }
  }
}

이런 결과를 가져올 수 있다. name이라는 필드는 R2-D2라는 문자열을 반환한다.

{
  "data": {
    "hero": {
      "name": "R2-D2",
      "friends": [
        {
          "name": "Luke Skywalker"
        },
        {
          "name": "Han Solo"
        },
        {
          "name": "Leia Organa"
        }
      ]
    }
  }
}

Arguments

REST와 다르게 각 필드과 오브젝트는 각각 인자를 받을 수 있다.

{
  human(id: "1000") {
    name
    # unit은 METER / FOOT의 enum 타입을 사용
    height(unit: FOOT)
  }
}

결과:

{
  "data": {
    "human": {
      "name": "Luke Skywalker",
      "height": 5.6430448
    }
  }
}

그럼 같은 필드에 대해 각각 다른 인자를 넘긴 결과값을 받아오기 위해서는 쿼리를 어떻게 짤까?

Aliases

별명을 이용하면 된다.

{
  empireHero: hero(episode: EMPIRE) {
    name
  }
  jediHero: hero(episode: JEDI) {
    name
  }
}

쿼리가 복잡해지면 인자만 다를 때 복잡한 쿼리를 계속 적어줘야한다. 중복되는 쿼리를 사용할 수 없을까?

Fragments

그럴 때 fragment를 선언하여 가져오려는 쿼리를 dry하게 작성할 수 있다.

{
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  appearsIn
  friends {
    name
  }
}

실습: https://beta.pokeapi.co/graphql/console/

피카츄(pikachu), 파이리(charmander), 꼬부기(squirtle)의 키, 몸무게, 기술의 이름(5 개까지)를 반환해보자.

  1. 각각 다른 Alias로 받아오기
  2. 쿼리 필드를 반복하지 않기

fragments에 변수 사용법

query 작성시에 값을 정의한다.

# $first라는 변수에 Int형 값 3을 저장
query HeroComparison($first: Int = 3) {
  leftComparison: hero(episode: EMPIRE) {
    ...comparisonFields
  }
  rightComparison: hero(episode: JEDI) {
    ...comparisonFields
  }
}

fragment comparisonFields on Character {
  name
  # 여기서 이렇게 정의한 변수를 사용 가능함
  friendsConnection(first: $first) {
    totalCount
    edges {
      node {
        name
      }
    }
  }
}

Operation name

query 작성시에는 query 키워드와 query의 이름을 지어줘야한다. 위의 몇몇 예제처럼 생략할 수도 있지만 대체로 햇갈리지 않게 하기 위해 적어준다.

키워드 종류는 query, mutation, subcription이 있다.

Variables

query에 제공하는 인자 값은 주로 가변적일 것이다. 그러므로 인자 값을 직접 쿼리에 작성하는 것은 별로 도움이 되지 않는다. 이때 변수를 정의하여 사용한다.

  1. 현재 작성된 정적 값을 $변수명 형태로 교체한다.
  2. $변수명을 query에 선언한다.
  3. 변수명: 값 JSON 형태로 전달

모든 변수는 스칼라 값이거나 ,enum, 혹은 입력 객체형이어야 한다.

존재하는 타입형: Int, Boolean, String, DateTime, Float 배열로 작성하려면: [Int] 이런식으로 쓸 수 있다.

변수 형 옆에 !를 붙여서 필수로 필요한 값임을 명시할 수 있다. 변수 형 옆에 = '기본값' 할 수 있다.

Directives

특정 조건에 의해 내부 쿼리 구조를 다르게 해야할 때가 있다.

  1. @include(if: boolean)을 이용하여 결과에 포함할지 결정
  2. @skip(if: boolean)을 이용하여 결과에 포함하지 않을지 결정
query Hero($episode: Episode, $withFriends: Boolean!) {
  hero(episode: $episode) {
    name
    friends @include(if: $withFriends) {
      name
    }
  }
}

실습: https://beta.pokeapi.co/graphql/console/

피카츄(pikachu), 파이리(charmander), 꼬부기(squirtle)의 키, 몸무게, 기술의 이름(N 개까지)를 반환해보자.

  1. 몬스터 이름과, N개는 변수로 선언하기
  2. withAccuracy 변수로 기술의 정확도도 함께 반환할지 판단

Mutations

서버의 데이터를 조작해야할 때 사용

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) {
  createReview(episode: $ep, review: $review) {
    stars
    commentary
  }
}

params

{
  "ep": "JEDI",
  "review": {
    "stars": 5,
    "commentary": "This is a great movie!"
  }
}

반환되는 것은 갱신 후의 데이터이다.

$review 변수에 할당된 것은 scalar 값이 아닌 input object type 임에 유의하자. 자세한 사항은 [[GraphQL - Schemas and Types]]에서 알아보자

query와 mutation의 공통점은 모두 여러개의 field를 가지질 수 있다는 점이다.

차이점은 query는 병렬로 실행될 수 있지만 mutation은 그렇지 않다는 점이다. 이로써 race condition을 방지할 수 있다.

Inline Fragments

interface나 union type인 field를 반환할 때 사용

query HeroForEpisode($ep: Episode!) {
  # Character는 Droid거나 Human임
  hero(episode: $ep) {
    name
    # Droid에만 있는 필드
    ... on Droid {
      primaryFunction
    }
    # Human에만 있는 필드
    ... on Human {
      height
    }
  }
}

Meta fields

어떤 타입을 받을지 모를때 __typename 이라는 meta field를 아무곳에서 요청할 수 있다.

  search(text: "an") {
    __typename
    ... on Human {
      name
    }
    ... on Droid {
      name
    }
    ... on Starship {
      name
    }
  }
}

결과

{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "Han Solo"
      },
      {
        "__typename": "Human",
        "name": "Leia Organa"
      },
      {
        "__typename": "Starship",
        "name": "TIE Advanced x1"
      }
    ]
  }
}

-> [[GraphQL - Schemas and Types]]

Referred in

GraphQL - Query and Mutation